package com.shaoyu.spring.study.dto;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Description:
 * @author: shaoyu1
 * @date: 2020/11/5 14:05:29
 */
public class BasicData implements Serializable {

    protected boolean containsProperty(Class claz,String filedname){
        try{
            return claz.getDeclaredField(filedname)!=null;
        }catch (NoSuchFieldException e){
            return false;
        }
    }
    public boolean containsProperty(String filedname){
        return containsProperty(this.getClass(),filedname);
    }
    /**
     * 获取自身的某属性值
     * @param filedName
     * @param <T>
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public  <T> T get(String filedName) throws  InvocationTargetException, IllegalAccessException {
        return get(this.getClass(),filedName,this);
    }
    /**
     * 获取某对象的属性值
     * @param filedName
     * @param source
     * @param <T>
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public  <T> T get(String filedName,Object source) throws  InvocationTargetException, IllegalAccessException {
        return get(source.getClass(),filedName,source);
    }
    protected <T> T get(Class claz,String filedName,Object source)throws  InvocationTargetException, IllegalAccessException{
        if(containsProperty(claz,filedName)){
            try{
                return (T)getPropertyGetMethod(claz,filedName).invoke(source);
            }catch (NullPointerException  e){
                throw new RuntimeException("属性"+filedName+"没有对应的get方法");
            }
        }else{
            Class superclass = claz.getSuperclass();
            if(superclass.equals(Object.class)){
                return null;
            }
            return get(superclass,filedName,source);
        }
    }

    /**
     * 给自身设置属性
     * @param filedName
     * @param property
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public boolean set(String filedName,Object property)throws  InvocationTargetException, IllegalAccessException {
        return set(this.getClass(),filedName,this,property);
    }

    /**
     * 给某个对象设置属性
     * @param filedName
     * @param source
     * @param property
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public boolean set(String filedName,Object source,Object property)throws  InvocationTargetException, IllegalAccessException {
        return set(source.getClass(),filedName,source,property);
    }
    protected boolean set(Class clz,String filedName,Object source,Object property)throws  InvocationTargetException, IllegalAccessException {
        if(containsProperty(clz,filedName)){
            try{
                getPropertySetMethod(clz,filedName).invoke(source,property);
                return true;
            }catch (NullPointerException e){
                throw new RuntimeException("属性"+filedName+"没有对应的set方法");
            }
        }else {
            Class superclass = clz.getSuperclass();
            if(superclass.equals(Object.class)){
                return false;
            }
            return set(superclass,filedName,source,property);
        }
    }


    protected Method getPropertyGetMethod(Class<?> type, String filedName) {
        Method[] methods = type.getMethods();
        for (Method method : methods) {
            if (method.getParameterTypes().length != 0)
                continue;
            if (method.getName().equalsIgnoreCase("get" + filedName)) {
                method.setAccessible(true);
                return method;
            }
            if ((Boolean.class.isAssignableFrom(method.getReturnType()) || "boolean".equals(method.getReturnType().getName())) && method.getName().equalsIgnoreCase("is" + filedName)) {
                method.setAccessible(true);
                return method;
            }
        }
        return null;
    }
    protected Method getPropertySetMethod(Class<?> type, String filedName) {
        Method[] methods = type.getMethods();
        for (Method method : methods) {
            if (method.getParameterTypes().length != 1)
                continue;
            if (method.getName().equalsIgnoreCase("set" + filedName)) {
                method.setAccessible(true);
                return method;
            }
            if ((Boolean.class.isAssignableFrom(method.getParameterTypes()[0]) || "boolean".equals(method.getParameterTypes()[0].getName())) && method.getName().equalsIgnoreCase("set" + filedName.replace("is", ""))) {
                method.setAccessible(true);
                return method;
            }
        }
        return null;
    }
}
